package com.lazydong.apiforward.client.gui.pages.appmain;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.lazydong.apiforward.client.ApiForwardClient;
import com.lazydong.apiforward.client.framework.PageAbility;
import com.lazydong.apiforward.client.framework.PageContainer;
import com.lazydong.apiforward.client.framework.PageEvent;
import com.lazydong.apiforward.client.framework.PageInfo;
import com.lazydong.apiforward.client.framework.annotation.MainPage;
import com.lazydong.apiforward.client.global.GlobalData;
import com.lazydong.apiforward.client.gui.constant.CommonConstant;
import com.lazydong.apiforward.client.gui.enums.PageEventEnum;
import com.lazydong.apiforward.client.gui.enums.PageInfoEnum;
import com.lazydong.apiforward.client.gui.pages.AppBaseConfig;
import com.lazydong.apiforward.gateway.ApiForwardGatewayApplication;
import com.lazydong.apiforward.gateway.StartupCompleted;
import com.lazydong.apiforward.client.gui.util.*;
import com.lazydong.gui.layout.Margin;
import com.lazydong.gui.layout.Size;
import com.lazydong.gui.layout.linear.LinearLayoutUtil;
import com.sun.jna.platform.win32.GL;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@MainPage
public class AppMainPage extends PageAbility<AppMainPageConfig> implements StartupCompleted {
    private static final int windowWidth = 600;
    private static final int windowHeight = 800;

    private static final JComboBox<Environment> envComboBox = new JComboBox<>();

    private JTabbedPane childJPanel;

    private final JLabel serviceStatusLabel = new JLabel("路由服务正在启动中...");

    private final JLabel tipLabel = new JLabel();

    private static final JButton update = new JButton("更新");

    private static final JButton browser = new JButton("打开浏览器访问");

    private final MainButtonListener mainButtonListener = new MainButtonListener();

    private static AppMainPageConfig globalAppMainConfig;

    private static final String def_title = "接口调试辅助工具";

    @Override
    public PageInfo getPageInfoEnum() {
        return PageInfoEnum.AppMain;
    }

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public void initConfig() {
        if (!FileUtil.exist(PageInfoEnum.AppMain.configFilePath())) {
            AppBaseConfig appBaseConfig = new AppBaseConfig();
            appBaseConfig.appTitle = def_title;
            appBaseConfig.browserPath = "";
            String jsonPrettyStr = JSONUtil.toJsonPrettyStr(appBaseConfig);
            FileUtil.writeString(jsonPrettyStr, PageInfoEnum.AppMain.configFilePath(), StandardCharsets.UTF_8);
        }
        if (!FileUtil.exist(PageInfoEnum.AppMain.runDataPath())) {
            Field[] fields0 = ReflectUtil.getFields(AppBaseConfig.class);
            List<String> appBaseFields = Arrays.stream(fields0).map(Field::getName).toList();
            Field[] fields1 = ReflectUtil.getFields(AppMainPageConfig.class);
            AppMainPageConfig config = new AppMainPageConfig();
            config.environmentList = new ArrayList<>();
            Environment environment0 = new Environment();
            environment0.envName = "";
            environment0.envDomain = "";
            environment0.envIp = "";
            config.environmentList.add(environment0);
            Environment environment1 = new Environment();
            config.environmentList.add(environment1);
            for (Field field : fields1) {
                String name = field.getName();
                if(appBaseFields.contains(name)) {
                    ReflectUtil.setFieldValue(config, field, null);
                }
            }
            String jsonPrettyStr = JSONUtil.toJsonPrettyStr(config);
            FileUtil.writeString(jsonPrettyStr, PageInfoEnum.AppMain.runDataPath(), StandardCharsets.UTF_8);
        }
    }

    @Override
    public AppMainPageConfig loadConfig() {
        String jsonStr = FileUtil.readString(PageInfoEnum.AppMain.runDataPath(), StandardCharsets.UTF_8);
        AppMainPageConfig appMainPageConfig = JSONUtil.toBean(jsonStr, AppMainPageConfig.class);

        globalAppMainConfig = appMainPageConfig;
        return appMainPageConfig;
    }

    @Override
    public JTabbedPane getChildJPanel() {
        return childJPanel;
    }

    @Override
    public void buildPage(JPanel parentJPanel, AppMainPageConfig config) {
        GlobalData.APP_MAIN_CONFIG.set(config);
        // 初始化窗口
        JFrame jFrame = new JFrame();
        GlobalData.GLOBAL_FRAME.set(jFrame);
        jFrame.setTitle(StrUtil.isBlank(config.appTitle) ? def_title : config.appTitle);
        // 设置图标
        String iconPath = CommonConstant.CURRENT_DIR + File.separator + "AppIcon.png";
        if (!FileUtil.exist(iconPath)) {
            InputStream inputStream = JarResFileCopyUtil.loadResourceInputStream(null, "AppIcon.png");
            BufferedOutputStream outputStream = FileUtil.getOutputStream(iconPath);
            IoUtil.copy(inputStream, outputStream);
            IoUtil.close(outputStream);
            IoUtil.close(inputStream);
        }
        ImageIcon imageIcon = new ImageIcon(iconPath);
        jFrame.setIconImage(imageIcon.getImage());
        // 设置窗口的位置和大小
        jFrame.setBounds(400, 300, windowWidth, windowHeight);
        Container contentPane = jFrame.getContentPane();
        // 中心面板大小大概比 jFrame（除去标题等元素外） 的大小要小 （宽20:高40）试出来的
        contentPane.setSize(windowWidth - 20, windowHeight - 40);
        addContentPaneLayout(contentPane, config);
        jFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("点击了关闭按钮");
                ApiForwardClient.delPid();
            }
        });
        // 设置窗口是否可见
        jFrame.setVisible(true);
        // 设置窗口是否可以缩放
        jFrame.setResizable(false);
        /*
         * 设置窗口的相对位置。
         * 如果 comp 整个显示区域在屏幕内, 则将窗口放置到 comp 的中心;
         * 如果 comp 显示区域有部分不在屏幕内, 则将该窗口放置在最接近 comp 中心的一侧;
         * comp 为 null, 表示将窗口放置到屏幕中心。
         */
        jFrame.setLocationRelativeTo(null);
        /*
         * 设置窗口关闭按钮点击后的默认操作, 参考值:
         *     WindowConstants.DO_NOTHING_ON_CLOSE: 不执行任何操作。
         *     WindowConstants.HIDE_ON_CLOSE: 隐藏窗口（不会结束进程）, 再次调用 setVisible(true) 将再次显示。
         *     WindowConstants.DISPOSE_ON_CLOSE: 销毁窗口, 如果所有可显示的窗口都被 DISPOSE, 则可能会自动结束进程。
         *     WindowConstants.EXIT_ON_CLOSE: 退出进程。
         */
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jFrame.setLayout(null);
    }

    private void addContentPaneLayout(Container contentPane, AppMainPageConfig config) {
        LinearLayoutUtil.setVLayout(contentPane);
        // 上面兜底环境选择、以及服务状态、更新按钮、打开浏览器按钮
        JPanel oneLayout = new JPanel();
        LinearLayoutUtil.addComponent(contentPane, oneLayout, Size.ofHeightRatio(5), Margin.ofTopRatio(1));
        oneLayout(oneLayout, config.environmentList);

        // 中间做提示信息
        JPanel twoLayout = new JPanel();
        LinearLayoutUtil.addComponent(contentPane, twoLayout, Size.ofHeightRatio(3));
        twoLayout(twoLayout);

        // 下面tab页面做展示
        childJPanel = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
        LinearLayoutUtil.addComponent(contentPane, childJPanel, Size.ofRatio(100, 95));
        //为选项卡添加监听器
        childJPanel.addChangeListener(new JTabbedPaneChangeListener());
    }

    private void oneLayout(JPanel oneLayout, List<Environment> environmentList) {
        LinearLayoutUtil.setHLayout(oneLayout);

        JLabel huan = new JLabel("环境");
        LinearLayoutUtil.addComponent(oneLayout, huan, Size.ofRatio(5, 80), Margin.ofLeftRatio(2));
        // 兜底环境
        envComboBox.addItemListener(new ComboBoxItemListener());
        for (Environment environment : environmentList) {
            envComboBox.addItem(environment);
        }
        LinearLayoutUtil.addComponent(oneLayout, envComboBox, Size.ofRatio(20, 80));

        // 是否拦截域名
        JLabel blocker = new JLabel("是否拦截域名");
        LinearLayoutUtil.addComponent(oneLayout, blocker, Size.ofRatio(13, 90), Margin.ofLeftRatio(2));

        RadioItemListener radioItemListener = new RadioItemListener();
        ButtonGroup buttonGroup = new ButtonGroup();
        JRadioButton no = new JRadioButton("否");
        no.setSelected(true);
        no.setActionCommand("no");
        no.addItemListener(radioItemListener);
        buttonGroup.add(no);
        LinearLayoutUtil.addComponent(oneLayout, no, Size.ofRatio(7, 90));
        JRadioButton yes = new JRadioButton("是");
        yes.setActionCommand("yes");
        yes.addItemListener(radioItemListener);
        buttonGroup.add(yes);
        LinearLayoutUtil.addComponent(oneLayout, yes, Size.ofRatio(7, 90));


        // 服务状态提示
//        LinearLayoutUtil.addComponent(oneLayout, serviceStatusLabel, Size.ofRatio(42, 90), Margin.ofLeftRatio(2));
        // 软件更新
        update.setEnabled(false);
        update.setActionCommand("updateApp");
        update.addActionListener(mainButtonListener);
        LinearLayoutUtil.addComponent(oneLayout, update, Size.ofRatio(11, 80), Margin.ofLeftRatio(10));
        // 打开浏览器

        browser.setActionCommand("openBrowser");
        browser.addActionListener(mainButtonListener);
        LinearLayoutUtil.addComponent(oneLayout, browser, Size.ofRatio(21, 100), Margin.ofLeftRatio(1));
    }

    private void twoLayout(JPanel twoLayout) {
        LinearLayoutUtil.setHLayout(twoLayout);
        JLabel tishi = new JLabel("提示:");
        LinearLayoutUtil.addComponent(twoLayout, tishi, Size.ofRatio(5, 90), Margin.ofLeftRatio(4));
        LinearLayoutUtil.addComponent(twoLayout, tipLabel, Size.ofRatio(95, 90), Margin.ofLeftRatio(1));
    }

    @Override
    public void afterBuildPage() {
        childJPanel.setEnabled(false);
        browser.setEnabled(false);
        envComboBox.setEnabled(false);
        DomainUtil.updateLocalHosts();
        ThreadUtil.execAsync(() -> {
            // 启动路由服务
            try {
                ApiForwardGatewayApplication.main(new String[0]);
            } catch (Exception e) {
                serviceStatusLabel.setText("启动服务失败");
            }
        });
    }

    @Override
    public void afterServiceStart() {
        GlobalData.ROUTE_SERVER_STATUS.set(true);
        serviceStatusLabel.setText("服务已启动");
        childJPanel.setEnabled(true);
        envComboBox.setEnabled(true);
        browser.setEnabled(true);

        RouteUpdateUtil.updateEnvironmentRoute();

        ThreadUtil.execAsync(() -> {
            // 检测软件更新
            Optional<String> appNewVersion = AppUpdateUtil.getAppNewVersion();
            if (appNewVersion.isEmpty()) {
                if (FileUtil.exist(CommonConstant.UPDATE_SUCCESS_FLAG)) {
                    FileUtil.del(CommonConstant.UPDATE_DIR);
                }
                return;
            }
            boolean updateExe = AppUpdateUtil.downUpdateExe(appNewVersion.get());
            if (updateExe) {
                update.setEnabled(true);
                PageContainer.sendAsyncEvent(PageEventEnum.MAIN_PAGE_TIP, "检测到新版本 " + appNewVersion.get());
            } else {
                PageContainer.sendAsyncEvent(PageEventEnum.MAIN_PAGE_TIP, "辅助更新程序下载失败");
            }
        });
    }

    @Override
    public void monitorEvent(PageEvent pageEvent, String text) {
        String eventCode = pageEvent.getCode();
        if (PageEventEnum.MAIN_PAGE_TIP.getCode().equals(eventCode)) {
            tipLabel.setText(text);
            return;
        }
    }

    @Override
    public void onStartupCompleted() {
        PageContainer.afterServiceStart();
    }

    private static class MainButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String actionCommand = e.getActionCommand();
            if ("openBrowser".equals(actionCommand)) {
                String openBrowserUrl = GlobalData.getOpenBrowserUrl();
                if (StrUtil.isBlank(openBrowserUrl)) {
                    return;
                }
                WindowsUtil.openBrowser(openBrowserUrl, globalAppMainConfig.browserPath);
                return;
            }
            if ("updateApp".equals(actionCommand)) {
                AppUpdateUtil.openUpdateExe();
            }
        }
    }

    /**
     * 选项卡监听器
     */
    private static class JTabbedPaneChangeListener implements ChangeListener {
        @Override
        public void stateChanged(ChangeEvent e) {
            JTabbedPane jTabbedPane = (JTabbedPane) e.getSource();
            int selectedIndex = jTabbedPane.getSelectedIndex();
            System.out.println(selectedIndex);
        }
    }

    /**
     * 下拉框监听器
     */
    private static class ComboBoxItemListener implements ItemListener {
        @Override
        public void itemStateChanged(ItemEvent e) {
            if (ItemEvent.SELECTED != e.getStateChange()) {
                return;
            }
            Environment environment = (Environment) e.getItem();
            System.out.println("切换环境: " + environment.envName);
            String envDomain = environment.envDomain;
            if (StrUtil.isNotBlank(envDomain)) {
                GlobalData.GLOBAL_ENVIRONMENT.set(environment);
            } else {
                GlobalData.GLOBAL_ENVIRONMENT.set(null);
            }
            DomainUtil.updateLocalHosts();
            RouteUpdateUtil.updateEnvironmentRoute();
        }
    }

    /**
     * 下拉框监听器
     */
    private static class RadioItemListener implements ItemListener {
        @Override
        public void itemStateChanged(ItemEvent e) {
            if (ItemEvent.SELECTED != e.getStateChange()) {
                return;
            }
            JRadioButton item = (JRadioButton) e.getItem();
            String actionCommand = item.getActionCommand();
            if ("yes".equals(actionCommand)) {
                GlobalData.BLOCKER_STATUS.set(true);
            }
            if ("no".equals(actionCommand)) {
                GlobalData.BLOCKER_STATUS.set(false);
            }
            DomainUtil.updateLocalHosts();
            RouteUpdateUtil.updateEnvironmentRoute();
        }
    }

}